﻿#include "geom/geom_surface.h"

CAGD::BPnt CAGD::GeomSurface::Value(double u, double v) const
{
    BPnt P;
    this->D0(u, v, P);
    return P;
}

CAGD::BPnt CAGD::GeomSurface::Value(const BPnt2d &p) const
{
    return Value(p.X(), p.Y());
}

CAGD::BVec CAGD::GeomSurface::Normal(double u, double v) const
{
    BPnt P;
    BVec DU, DV;
    this->D1(u, v, P, DU, DV);
    return (DU % DV).Normalized();
}

CAGD::BVec CAGD::GeomSurface::Normal(const BPnt2d &p) const
{
    return Normal(p.X(), p.Y());
}

CAGD::GeomType CAGD::GeomSurface::Type() const
{
    return GeomType::SURFACE;
}

Handle(CAGD::TriangleMesh) CAGD::GeomSurface::Triangulate(Handle(GeomSurface) surface, int nu, int nv)
{
    double bu, eu, bv, ev;
    surface->Bounds(bu, eu, bv, ev);

    TriangleMesh *tri = new TriangleMesh;
    auto &vertices = tri->vertices;
    auto &normals = tri->normals;
    auto &triangles = tri->triangles;

    // 构建索引
    int m = nu;
    int n = nv;
    for (int i = 0; i < m - 1; i++)
    {
        for (int j = 0; j < n - 1; j++)
        {
            // 四边形分割成两个三角形
            triangles.push_back(Triangle{i * n + j, i * n + j + 1, (i + 1) * n + j});
            triangles.push_back(Triangle{i * n + j + 1, (i + 1) * n + j + 1, (i + 1) * n + j});
        }
    }

    // 构建顶点和法向
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            int k = i * n + j;

            float u = bu + (eu - bu) / (m - 1) * i;
            float v = bv + (ev - bv) / (n - 1) * j;

            auto P = surface->Value(u, v);
            auto N = surface->Normal(u, v);
            vertices.push_back(P);
            normals.push_back(N);
        }
    }
    return Handle(TriangleMesh)(tri);
}

std::vector<CAGD::BPnt> CAGD::GeomSurface::UniformPointSample(Handle(GeomSurface) surface, int nu, int nv)
{
    double bu, eu, bv, ev;
    surface->Bounds(bu, eu, bv, ev);

    std::vector<BPnt> points;
    double du = eu - bu;
    double dv = ev - bv;
    for (int i = 0; i < nu; i++)
    {
        double u = bu + i * 1.0 / (nu - 1) * du;
        for (int j = 0; j < nv; j++)
        {
            double v = bv + j * 1.0 / (nv - 1) * dv;
            points.push_back(surface->Value(u, v));
        }
    }
    return points;
}

std::vector<CAGD::BVec> CAGD::GeomSurface::UniformNormalSample(Handle(GeomSurface) surface, int nu, int nv)
{
    double bu, eu, bv, ev;
    surface->Bounds(bu, eu, bv, ev);

    std::vector<BVec> normals;
    double du = eu - bu;
    double dv = ev - bv;
    for (int i = 0; i < nu; i++)
    {
        double u = bu + i * 1.0 / (nu - 1) * du;
        for (int j = 0; j < nv; j++)
        {
            double v = bv + j * 1.0 / (nv - 1) * dv;
            normals.push_back(surface->Normal(u, v));
        }
    }
    return normals;
}

std::vector<CAGD::BPnt> CAGD::GeomSurface::IsoU(Handle(GeomSurface) surface, double u, int size)
{
    double bu, eu, bv, ev;
    surface->Bounds(bu, eu, bv, ev);
    std::vector<BPnt> points;
    for (int i = 0; i < size; i++)
    {
        float v = bv + (ev - bv) / (size - 1) * i;
        auto P = surface->Value(u, v);
        points.push_back(P);
    }
    return points;
}

std::vector<CAGD::BPnt> CAGD::GeomSurface::IsoV(Handle(GeomSurface) surface, double v, int size)
{
    double bu, eu, bv, ev;
    surface->Bounds(bu, eu, bv, ev);
    std::vector<BPnt> points;
    for (int i = 0; i < size; i++)
    {
        float u = bu + (eu - bu) / (size - 1) * i;
        auto P = surface->Value(u, v);
        points.push_back(P);
    }
    return points;
}